#include <iostream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include "util.hpp"

using std::cerr;
using std::cout;
using std::endl;
using std::string;
using std::vector;

const string src_path = "./data/input/";         // 要解析的网页的路径
const string output = "./data/raw_html/raw.txt"; // 解析出的内容存放的路径

// 文档结构体，存储文件标题，文件内容，文档在官网中的url
typedef struct DocInfo
{
    string title;
    string content;
    string url;
} DocInfo;

bool EnumFile(const string &src_path, vector<string> &files_lists)
{
    // 使用boost库的path类
    // 命名空间重命名
    namespace fs = boost::filesystem;
    fs::path root_path(src_path); // 要枚举的文件目录
    if (!fs::exists(root_path))
    {
        cerr << "src_path is not exist!" << endl;
        return false;
    }
    // 定义迭代器方便取文件路径，定义空迭代器，方便判断遍历结束
    fs::recursive_directory_iterator end;
    for (fs::recursive_directory_iterator iter(root_path); iter != end; iter++)
    {
        // 如果不是普通文件就跳过，html文件都是普通文件
        if (!fs::is_regular_file(*iter))
            continue;
        // 判断当前遍历到的文件的后缀是不是.html
        if (iter->path().extension() != ".html")
            continue;
        files_lists.push_back(iter->path().string());
    }
    return true;
}

bool ParseTitle(const string &result, string &title)
{
    size_t begin = result.find("<title>");
    if (begin == string::npos)
        return false;
    size_t end = result.find("</title>");
    if (end == string::npos)
        return false;
    if (begin > end)
        return false;
    begin += string("<title>").size();
    title += result.substr(begin, end - begin);
    return true;
}
bool ParseContent(const string &result, string &content)
{
    bool content_state = false; // 简易状态机,当在标签状态时不读取,在内容状态时读取文件
    for (char c : result)
    {
        if (c == '<')
            content_state = false;
        else if (c == '>')
            content_state = true;
        else if (content_state)
        {
            if (c == '\n')
                c = ' '; // 将\n转化成空格,因为后续的文件之间的分割符采用\n
            content += c;
        }
    }
    return true;
}
bool ParseUrl(const string &file_path, string &url)
{
    static const string url_head = "https://www.boost.org/doc/libs/1_81_0/doc/html/";
    string url_tail = file_path.substr(src_path.size());
    url = url_head + url_tail;
    return true;
}
bool ParseHtml(const vector<string> &files_lists, vector<DocInfo> &doc_results)
{
    for (auto &files : files_lists)
    {
        string results;
        // 1.读取html文件
        if (!ns_util::FileUtil::ReadFile(files, results))
            return false;

        // 提取文件信息放入文件结构体Doc_Info中
        DocInfo doc;

        // 2.提取string中的title
        if (!ParseTitle(results, doc.title))
            return false;

        // 3.读取文件内容
        if (!ParseContent(results, doc.content))
            return false;

        // 4.拼接url=url_head(官网去看看1_81_0版本文档url头部）+url_tail（拼接到本地的资源目录）
        if (!ParseUrl(files, doc.url))
            return false;
        doc_results.push_back(std::move(doc)); // 防止拷贝，提高效率
    }
    // for debug
    // for (auto &doc : doc_results)
    //     cout << "title:" << doc.title << endl
    //          << "content:" << doc.content << endl
    //          << "url:" << doc.url << endl;
    return true;
}
bool SaveHtml(vector<DocInfo> &results, const string &output)
{
    std::ofstream out(output.c_str(), std::ios_base::out);
    if (!out.is_open())
    {
        cerr << "open " << output << " failed!" << endl;
        return false;
    }
    for (auto &doc : results)
    {
        string doc_str = doc.title;
        doc_str += '\3';
        doc_str += doc.content;
        doc_str += '\3';
        doc_str += doc.url;
        doc_str += '\n'; // 文档之间的分割符，方便按行读取
        out.write(doc_str.c_str(), doc_str.size());
    }
    out.close();
    return true;
}

int main()
{
    vector<string> files_lists; // 文件路径列表
    // 1.递归式地遍历所有文件，将每个html文件名带路径保存在files_list中，方便逐个文件读取
    if (!EnumFile(src_path, files_lists))
    {
        cerr << "enum file name error!" << endl;
        return 1;
    }

    // 2.从文件files_lists中读取每个文件的内容，并进行解析，
    // 解析成DocInfo结构体，存储在数组中,这个过程就是去标签
    vector<DocInfo> results;
    if (!ParseHtml(files_lists, results))
    {
        cerr << "parse file name error!" << endl;
        return 2;
    }

    // 3.把解析完的各个文件成的结构体，写入到output，
    // 将\3作为文档结构体成员的分隔符，按照\n作为每个文件的分割符，方便逐行读取(getline)
    if (!SaveHtml(results, output))
    {
        cerr << "save html to output error" << endl;
        return 3;
    }

    cout << "write to raw.txt completed!" << endl;
    return 0;
}